#include "acceptiobuffer.hpp"
#include "logger.hpp"

namespace oraysock5 {
static void ioreadcb(struct bufferevent* bev, void* ptr)
{
    AcceptIoBuffer* p = reinterpret_cast<AcceptIoBuffer*>(ptr);
    p->io_readcb();
}

static void iowritecb(struct bufferevent* bev, void* ptr)
{
    AcceptIoBuffer* p = reinterpret_cast<AcceptIoBuffer*>(ptr);
    p->io_writecb();
}

static void ioeventcb(struct bufferevent* bev, short events, void* ptr)
{
    AcceptIoBuffer* p = reinterpret_cast<AcceptIoBuffer*>(ptr);
    p->io_eventcb(events);
}

AcceptIoBuffer::AcceptIoBuffer(std::shared_ptr<EventBase> base,
    evutil_socket_t fd)
    : EventBuffer(base, fd, BEV_OPT_CLOSE_ON_FREE)
{
    setcb(ioreadcb, iowritecb, ioeventcb, this);
    enabled(EV_READ | EV_WRITE | EV_PERSIST);
}

void AcceptIoBuffer::io_readcb()
{
    std::shared_ptr<AcceptNewFd> aptnewfd = newfd_.lock();
    if (aptnewfd != nullptr) {
        InputResult ret = aptnewfd->input();
        if (ret == InputResult::INITIATIVE_CLOSE) {
            aptnewfd->close(CloseType::SERVER_CLOSE);
        } else if (ret == InputResult::PASSIVE_CLOSE) {
            aptnewfd->close(CloseType::CLIENT_CLOSE);
        }
    }
}

void AcceptIoBuffer::io_writecb()
{
    std::shared_ptr<AcceptNewFd> aptnewfd = newfd_.lock();
    if (aptnewfd != nullptr) {
        int ret = aptnewfd->output();
        if (ret == -1) {
            aptnewfd->close(CloseType::SERVER_CLOSE);
        }
    }
}

void AcceptIoBuffer::io_eventcb(short events)
{
    std::shared_ptr<AcceptNewFd> aptnewfd = newfd_.lock();
    if (aptnewfd != nullptr) {
        if (events & BEV_EVENT_EOF) {
            aptnewfd->close(CloseType::CLIENT_CLOSE);
        } else if (events & (BEV_EVENT_ERROR | BEV_EVENT_READING | BEV_EVENT_WRITING | BEV_EVENT_TIMEOUT)) {
            LOG_WARN << evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR());
            aptnewfd->close(CloseType::SERVER_CLOSE);
        }
    }
}

}
